import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import socket
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import time


class VotingClientGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("投票系统客户端")
        self.root.geometry("800x600")
        self.root.resizable(True, True)
        self.key = None
        self.iv = None
        self.socket = None

        # 创建主框架
        self.main_frame = ttk.Frame(root, padding="20")
        self.main_frame.pack(fill=tk.BOTH, expand=True)

        # 连接服务器部分
        self.connection_frame = ttk.LabelFrame(self.main_frame, text="服务器连接", padding="10")
        self.connection_frame.pack(fill=tk.X, pady=10)

        ttk.Label(self.connection_frame, text="服务器IP:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.ip_entry = ttk.Entry(self.connection_frame, width=20)
        self.ip_entry.grid(row=0, column=1, padx=5, pady=5)
        self.ip_entry.insert(0, "127.0.0.1")

        ttk.Label(self.connection_frame, text="端口:").grid(row=0, column=2, padx=5, pady=5, sticky=tk.W)
        self.port_entry = ttk.Entry(self.connection_frame, width=10)
        self.port_entry.grid(row=0, column=3, padx=5, pady=5)
        self.port_entry.insert(0, "9999")

        self.connect_btn = ttk.Button(self.connection_frame, text="连接服务器", command=self.connect_server)
        self.connect_btn.grid(row=0, column=4, padx=10, pady=5)

        # 候选人信息显示
        self.candidates_frame = ttk.LabelFrame(self.main_frame, text="候选人信息", padding="10")
        self.candidates_frame.pack(fill=tk.BOTH, expand=True, pady=10)

        self.candidates_text = scrolledtext.ScrolledText(self.candidates_frame, wrap=tk.WORD, height=10)
        self.candidates_text.pack(fill=tk.BOTH, expand=True)
        self.candidates_text.config(state=tk.DISABLED)

        # 投票规则显示
        self.rules_frame = ttk.LabelFrame(self.main_frame, text="投票规则", padding="10")
        self.rules_frame.pack(fill=tk.X, pady=10)

        self.rules_label = ttk.Label(self.rules_frame, text="请先连接服务器获取投票规则")
        self.rules_label.pack(fill=tk.X, padx=5, pady=5)

        # 投票部分
        self.voting_frame = ttk.LabelFrame(self.main_frame, text="投票", padding="10")
        self.voting_frame.pack(fill=tk.X, pady=10)

        ttk.Label(self.voting_frame, text="用户ID:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.user_id_entry = ttk.Entry(self.voting_frame, width=20)
        self.user_id_entry.grid(row=0, column=1, padx=5, pady=5)

        ttk.Label(self.voting_frame, text="候选人ID(多个用逗号分隔):").grid(row=0, column=2, padx=5, pady=5,
                                                                            sticky=tk.W)
        self.candidates_entry = ttk.Entry(self.voting_frame, width=30)
        self.candidates_entry.grid(row=0, column=3, padx=5, pady=5)

        self.vote_btn = ttk.Button(self.voting_frame, text="提交投票", command=self.submit_vote, state=tk.DISABLED)
        self.vote_btn.grid(row=0, column=4, padx=10, pady=5)

        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        self.status_bar = ttk.Label(root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

        # 设置样式
        self.style = ttk.Style()
        self.style.configure("TButton", padding=6)
        self.style.configure("TLabel", padding=5)
        self.style.configure("TLabelframe.Label", font=('Arial', 10, 'bold'))

    def connect_server(self):
        try:
            server_ip = self.ip_entry.get().strip() or "127.0.0.1"
            server_port = int(self.port_entry.get().strip() or 9999)

            self.status_var.set(f"正在连接服务器 {server_ip}:{server_port}...")
            self.root.update()

            self.socket = socket.socket()
            self.socket.settimeout(5)
            self.socket.connect((server_ip, server_port))

            # 接收密钥和初始化向量
            key_iv = self.socket.recv(32)
            self.key, self.iv = key_iv[:16], key_iv[16:]

            # 接收候选人信息
            candidates_data = self.socket.recv(4096)
            candidates = self.decrypt(candidates_data, self.key)

            # 接收投票规则
            vote_info_data = self.socket.recv(1024)
            vote_info = self.decrypt(vote_info_data, self.key)

            # 更新UI
            self.candidates_text.config(state=tk.NORMAL)
            self.candidates_text.delete(1.0, tk.END)
            self.candidates_text.insert(tk.END, candidates)
            self.candidates_text.config(state=tk.DISABLED)

            self.rules_label.config(text=vote_info)
            self.vote_btn.config(state=tk.NORMAL)

            self.status_var.set(f"成功连接到服务器 {server_ip}:{server_port}")

        except Exception as e:
            messagebox.showerror("连接错误", f"无法连接到服务器: {str(e)}")
            self.status_var.set("连接失败")
            if self.socket:
                self.socket.close()
                self.socket = None

    def submit_vote(self):
        if not self.socket:
            messagebox.showerror("错误", "未连接到服务器")
            return

        user_id = self.user_id_entry.get().strip()
        if not user_id:
            messagebox.showwarning("输入错误", "用户ID不能为空")
            return

        cids = self.candidates_entry.get().strip()
        if not cids:
            messagebox.showwarning("输入错误", "候选人ID不能为空")
            return

        try:
            self.status_var.set("正在提交投票...")
            self.root.update()

            # 发送投票
            vote_data = f"VOTE|{user_id}|{cids}"
            encrypted_data = self.encrypt(vote_data, self.key, self.iv)
            self.socket.sendall(encrypted_data)

            # 接收响应
            response_data = self.socket.recv(4096)
            response = self.decrypt(response_data, self.key)

            messagebox.showinfo("投票结果", response)
            self.status_var.set("投票完成")

            # 清空输入框
            self.user_id_entry.delete(0, tk.END)
            self.candidates_entry.delete(0, tk.END)

        except Exception as e:
            messagebox.showerror("投票错误", f"投票失败: {str(e)}")
            self.status_var.set("投票失败")

    def encrypt(self, message, key, iv):
        cipher = AES.new(key, AES.MODE_CBC, iv)
        return iv + cipher.encrypt(pad(message.encode(), AES.block_size))

    def decrypt(self, data, key):
        try:
            iv, encrypted = data[:16], data[16:]
            cipher = AES.new(key, AES.MODE_CBC, iv)
            return unpad(cipher.decrypt(encrypted), AES.block_size).decode()
        except Exception:
            return "解密错误"

    def on_closing(self):
        if self.socket:
            self.socket.close()
        self.root.destroy()


if __name__ == "__main__":
    root = tk.Tk()
    app = VotingClientGUI(root)
    root.protocol("WM_DELETE_WINDOW", app.on_closing)
    root.mainloop()